package main

import (
	"errors"
	"fmt"
	"os"
)

type CircleQueue struct {
	maxSize int
	array   [4]int //数组
	head    int    //指向队列的队首
	tail    int    //指向数据的队尾
}

//入队列
func (cq *CircleQueue) PushQueue(val int) (err error) {
	if cq.IsFull() {
		return errors.New("queue full")
	}
	//分析出，cq.tail在队列尾部，但是不包含最后的元素
	cq.array[cq.tail] = val //把值给尾部
	cq.tail = (cq.tail + 1) % cq.maxSize
	return err
}

//出队列
func (cq *CircleQueue) PopQueue() (val int, err error) {
	if cq.IsEmpty() {
		return 0, errors.New("queue empty")
	}
	//取出数据，head是指向队首，并且包含队首元素
	val = cq.array[cq.head]
	cq.head = (cq.head + 1) % cq.maxSize
	return val, err
}

//判断环形队列是否满了
func (cq *CircleQueue) IsFull() bool {
	return (cq.tail+1)%cq.maxSize == cq.head
}

//判断环形队列是否为空
func (cq *CircleQueue) IsEmpty() bool {
	return cq.tail == cq.head
}

//取出环形队列有多少个元素
func (cq *CircleQueue) Size() int {
	return (cq.tail + cq.maxSize - cq.head) % cq.maxSize
}

//显示环形队列
func (cq *CircleQueue) ShowQueue() {
	fmt.Println("环形队列情况如下：")
	//取出当前队列有多少个元素
	size := cq.Size()
	if size == 0 {
		fmt.Println("队列为空")
	}
	//设计一个辅助变量，指向head
	tempHead := cq.head
	for i := 0; i < size; i++ {
		fmt.Printf("arr[%d]=%d\t\n", tempHead, cq.array[tempHead])
		tempHead = (tempHead + 1) % cq.maxSize
	}
	fmt.Println()
}

func main() {
	q := &CircleQueue{
		maxSize: 4,
		array:   [4]int{},
		head:    0,
		tail:    0,
	}
	//err := q.AddQueue(2)
	//fmt.Println(err)
	//q.ShowQueue()
	var key string
	var val int
	for {
		fmt.Println("1、输入add，表示添加数据到队列")
		fmt.Println("1、输入get，表示获取数据到队列")
		fmt.Println("1、输入show，表示展示数据到队列")
		fmt.Println("1、输入exit，表示退出")
		fmt.Scanln(&key)

		switch key {
		case "add":
			fmt.Println("输入你要入队列的数据")
			fmt.Scanln(&val)
			err := q.PushQueue(val)
			if err != nil {
				fmt.Println(err)
			}
		case "get":
			val, err := q.PopQueue()
			if err != nil {
				fmt.Println("err,", err)
			} else {
				fmt.Println("队列中取出的数据为:", val)
			}

		case "show":
			fmt.Println("当前队列的数据")
			q.ShowQueue()
		case "exit":
			os.Exit(0)

		}
	}
}
